package org.vordel.incubator.examples.management_api;

import java.util.ArrayList;
import java.util.Collection;

import com.vordel.es.ESPK;
import com.vordel.es.Entity;
import com.vordel.es.EntityStore;
import com.vordel.es.EntityType;
import com.vordel.es.Field;
import com.vordel.es.FieldType;
import com.vordel.es.Value;
import com.vordel.es.xes.PortableESPK;
import com.vordel.es.xes.PortableESPKFactory;
import com.vordel.trace.Trace;

public class ServiceManager extends EntityWrapperManager {

	ServiceManager(Session session) {
		super(session);
		// TODO Auto-generated constructor stub
	}

	@Override
	protected String getContainerEntityTypeName() {
		// TODO Auto-generated method stub
		return "NetService";
	}

	@Override
	protected String getContainerEntityName() {
		// TODO Auto-generated method stub
		return "Service";
	}

	@Override
	protected String getEntityTypeName() {
		// TODO Auto-generated method stub
		return "HTTP";
	}
	
	public HTTPService newHTTPService(String name) throws Exception {
		
		Entity httpServiceEntity = this.createEntity(name);
		return new HTTPService(httpServiceEntity,this);
	}
	
	public HTTPService getHTTPService(String name) throws Exception {
		
		Entity httpServiceEntity = this.getEntityByName(name);
		if (httpServiceEntity==null) {
			return null;
		}
		return new HTTPService(httpServiceEntity,this);
		
		
	}
	
	public HTTPSInterface getHTTPsInterface(String address, String port, HTTPService parent) throws Exception {
	
		Entity entity = this.getHTTPInterface("SSLInterface", address, port,parent);
		
		if (entity==null) {
			return null;
		}
		
		return new HTTPSInterface(entity, this);
	}
	
	public HTTPInterface getHTTPInterface(String address, String port, HTTPService parent) throws Exception {
		
		Entity entity = this.getHTTPInterface("InetInterface", address, port,parent);
		
		if (entity==null) {
			return null;
		}
		
		return new HTTPInterface(entity, this);
	}
	
	public Entity getHTTPInterface(String typeName, String address, String port, HTTPService parent) throws Exception {
	
		EntityStore es = this.session.getEntityStore();
		EntityType type = es.getTypeForName(typeName);
		
		FieldType addressFieldType = type.getFieldType("address");
		FieldType portFieldType = type.getFieldType("port");
		
		Field addressField = new Field(addressFieldType, "address");
		addressField.addValue(new Value(address));
		
		Field portField = new Field(portFieldType, "port");
		portField.addValue(new Value(port));
		
		Collection<ESPK> interfaces = es.findChildren(parent.entity.getPK(), new Field[] {addressField,portField}, type);
		
		if (interfaces==null || interfaces.size()==0) {
			return null;
		} 
		
		return es.getEntity(interfaces.iterator().next());
		
		
	}
	
	HTTPInterface createHTTPInterface(String address, String port, HTTPService service) throws Exception {
		Entity entity = this.createInetInterface("InetInterface", address, port, service);
		return new HTTPInterface(entity, this);
	}
	
	HTTPSInterface createHTTPsInterface(String address, String port, HTTPService service) throws Exception {
		Entity entity = this.createInetInterface("SSLInterface", address, port, service);
		return new HTTPSInterface(entity, this);
	}
	
	Entity createInetInterface(String type, String address, String port, HTTPService service) throws Exception {
		EntityStore es  = this.getSession().getEntityStore();
		EntityType httpServiceType = es.getTypeForName(type);
		Entity httpServiceEntity = new Entity(httpServiceType);
		
		httpServiceEntity.setStringField("address", address);
		httpServiceEntity.setStringField("port", port);
		
		ESPK httpServiceESPK = es.addEntity(service.getEntity().getPK(),httpServiceEntity);
		httpServiceEntity = es.getEntity(httpServiceESPK);
		
		return httpServiceEntity;
		
	}
	
	Entity getXMLFirewall(String uriprefix, HTTPService service) throws Exception {
		
		EntityStore es  = this.getSession().getEntityStore();
		EntityType xmlFirewallType = es.getTypeForName("XMLFirewall");
		
		FieldType uriPrefixType = xmlFirewallType.getFieldType("uriprefix");
		
		
		Field uriPrefixField = new Field(uriPrefixType, "uriprefix");
		uriPrefixField.addValue(new Value(uriprefix));
		
		Collection<ESPK> interfaces = es.findChildren(service.entity.getPK(), new Field[] {uriPrefixField}, xmlFirewallType);
		
		if (interfaces==null || interfaces.size()==0) {
			return null;
		} 
		
		Entity xmlFirewallEntity =  es.getEntity(interfaces.iterator().next());
		
		return xmlFirewallEntity;
		
	}
	
	Entity getWebServicePlugin(String name, HTTPService service) throws Exception {
		
		EntityStore es  = this.getSession().getEntityStore();
		EntityType webServicePluginType = es.getTypeForName("WebServicePlugin");
		
		FieldType uriPrefixType = webServicePluginType.getFieldType("uriprefix");
		
		
		Field uriPrefixField = new Field(uriPrefixType, "uriprefix");
		uriPrefixField.addValue(new Value(name));
		
		Trace.debug("Searching "+service.getEntity().getPK()+" for "+webServicePluginType.getName()+" uriprefix="+name);

		
		Collection<ESPK> interfaces = es.listChildren(service.getEntity().getPK(), webServicePluginType);
		
		if (interfaces==null || interfaces.size()==0) {
			return null;
		} 
		
		for (ESPK childESPK: interfaces) {
			
			Entity childEntity = es.getEntity(childESPK);
			String childURIPrefix = childEntity.getStringValue("uriprefix");
			
			if (childURIPrefix.equals(name)) {
				
				Trace.debug("Found WebServicePlugin with uriprefix="+name);
				return childEntity;
				
			} else {
				
				Trace.debug("Found WebServicePlugin with uriprefix="+childURIPrefix+"!="+name);
				
			}
			
		}
		
		return null;
		
	}
	
	Entity getPolicyForPath(String uriprefix, HTTPService service) throws Exception {
		
		 
		
		Entity xmlFirewallEntity =  this.getXMLFirewall(uriprefix, service);
	
		if (xmlFirewallEntity==null) {
			return null;
		}
		
		ESPK filterCircuitESPK = xmlFirewallEntity.getReferenceValue("filterCircuit");
		
		if (filterCircuitESPK==null || filterCircuitESPK == EntityStore.ES_NULL_PK) {
			return null;
		}
		
		Entity filterCircuitEntity = this.session.getEntityStore().getEntity(filterCircuitESPK);
		
		return filterCircuitEntity;
		
	}
	
	void addPolicyToPath(String uriprefix, HTTPService service, Policy policy) throws Exception {
		
		EntityStore es  = this.getSession().getEntityStore();
		EntityType xmlFirewallType = es.getTypeForName("XMLFirewall");
		
		Entity xmlFirewallEntity = new Entity(xmlFirewallType);
		xmlFirewallEntity.setStringField("uriprefix", uriprefix);
		
		PortableESPKFactory factory = PortableESPKFactory.newInstance();
		PortableESPK portableESPK = factory.createPortableESPK(es, policy.getEntity().getPK());
		
		
		xmlFirewallEntity.setReferenceField("filterCircuit", portableESPK);
		
	
		ESPK newKey = es.addEntity(service.entity.getPK(), xmlFirewallEntity);
		
		xmlFirewallEntity = es.getEntity(newKey);
		
		
	}
	
	private void addWebServicePolicyForPath(String uriprefix, HTTPService service, Policy policy, WebService ws, String name) throws Exception {
	
		
		EntityStore es  = this.getSession().getEntityStore();
		EntityType webServicePluginType = es.getTypeForName("WebServicePlugin");
		
		Entity webServicePluginEntity = new Entity(webServicePluginType);
		webServicePluginEntity.setStringField("uriprefix", name);
		webServicePluginEntity.setStringField("specifiedURL",uriprefix);
		webServicePluginEntity.setStringField("resolverMode", "specifiedURL");
		
		PortableESPKFactory factory = PortableESPKFactory.newInstance();
		PortableESPK portablePolicyESPK = factory.createPortableESPK(es, policy.getEntity().getPK());
		PortableESPK portableWebServiceESPK = factory.createPortableESPK(es, ws.getEntity().getPK());
		
		webServicePluginEntity.setReferenceField("filterCircuit", portablePolicyESPK);
		webServicePluginEntity.setReferenceField("webService", portableWebServiceESPK);
		
	
		ESPK newKey = es.addEntity(service.entity.getPK(), webServicePluginEntity);
		
		webServicePluginEntity = es.getEntity(newKey);
		
		
	}
	
	void setPolicyForPath(String uriprefix, HTTPService service, Policy policy) throws Exception {

		Entity xmlFirewallEntity =  this.getXMLFirewall(uriprefix, service);
		
		if (xmlFirewallEntity==null) {
			
			this.addPolicyToPath(uriprefix, service, policy);
			
		} else {
		
			EntityStore es = this.session.getEntityStore();
			PortableESPKFactory factory = PortableESPKFactory.newInstance();
			PortableESPK portableESPK = factory.createPortableESPK(es, policy.getEntity().getPK());
			
			
			xmlFirewallEntity.setReferenceField("filterCircuit", portableESPK);
			
			es.updateEntity(xmlFirewallEntity);
		}
		
	}
	
	void setWebServicePolicyForPath(String path, HTTPService service, Policy policy, WebService ws, String name) throws Exception  {
		
		Entity webServicePluginEntity =  this.getWebServicePlugin(name, service);
		if (webServicePluginEntity == null) {
			this.addWebServicePolicyForPath(path, service, policy, ws, name);
		}  else {
			
			EntityStore es = this.session.getEntityStore();
			PortableESPKFactory factory = PortableESPKFactory.newInstance();
			PortableESPK portablePolicyESPK = factory.createPortableESPK(es, policy.getEntity().getPK());
			PortableESPK portableWebServiceESPK = factory.createPortableESPK(es, ws.getEntity().getPK());
			
			webServicePluginEntity.setReferenceField("filterCircuit", portablePolicyESPK);
			webServicePluginEntity.setReferenceField("webService", portableWebServiceESPK);
			webServicePluginEntity.setStringField("specifiedURL", path);
			webServicePluginEntity.setStringField("resolverMode", "specifiedURL");
			
			es.updateEntity(webServicePluginEntity);
		}
		
	}
	
	Entity renameWebServicePolicy(HTTPService service, String name, String newName) throws Exception {
		
		Entity webServicePluginEntity =  this.getWebServicePlugin(name, service);
		
		if (webServicePluginEntity==null) {
			return null;
		}
		
		Entity newWebServicePluginEntity =  this.getWebServicePlugin(newName, service);
		
		if (newWebServicePluginEntity!=null) {
			Trace.error("Cannot rename the WebService policy "+name+" to "+newName+" because "+newName+" already exists.");
		}
		
		webServicePluginEntity.setStringField("uriprefix", newName);
		
		EntityStore es = this.session.getEntityStore();
		es.updateEntity(webServicePluginEntity);
		
		return es.getEntity(webServicePluginEntity.getPK());
		
	}

	public void setWebServicePath(String path, HTTPService service,
			WebService createdWebService) throws Exception {
		// TODO Auto-generated method stub
	
		Entity wsEntity = createdWebService.entity;
		EntityStore es = this.session.getEntityStore();
		
		Collection<ESPK> refs = es.findReferringEntities(wsEntity.getPK());
		
		for (ESPK ref: refs) {
			
			
			Entity refEntity = es.getEntity(ref);
			if (refEntity.getType().getName().equals("WebServicePlugin")) {
				
				refEntity.setStringField("specifiedURL", path);
				refEntity.setStringField("resolverMode", "specifiedURL");
				
				es.updateEntity(refEntity);
				
			}
			
			
		}
		
		
	}
	
	Policy getPolicyForWebService(HTTPService httpService, WebService ws) throws Exception {
		
		Entity serviceEntity = httpService.entity;
		EntityStore es = this.session.getEntityStore();
		
		Collection<ESPK> children = es.listChildren(serviceEntity.getPK(), es.getTypeForName("WebServicePlugin"));
		
		
		for (ESPK child: children) {
			
			Entity childEntity = es.getEntity(child);
			ESPK wsESPK = childEntity.getReferenceValue("webService");
			Entity wsEntity = es.getEntity(wsESPK);
			
			if (wsEntity.getPK().equals((ws.getEntity().getPK()))) {
			
				ESPK policyESPK = childEntity.getReferenceValue("filterCircuit");
				
				if (policyESPK==EntityStore.ES_NULL_PK) {
					Trace.info(childEntity+" filterCircuit references="+policyESPK);
					continue;
				}
				
				Entity policyEntity = es.getEntity(policyESPK); 
				Policy policy = new Policy(policyEntity,this.session.getPolicyManager());
				return policy;
				
			} else {
				
				System.out.println(wsEntity.getPK()+"!="+ws.getEntity().getPK());
				
			}
			
			
		}
		
				
		return null;
	}

	public Collection<WebService> listWebServices(HTTPService httpService) throws Exception {
		// TODO Auto-generated method stub
		
		Entity serviceEntity = httpService.entity;
		EntityStore es = this.session.getEntityStore();
		
		Collection<ESPK> children = es.listChildren(serviceEntity.getPK(), es.getTypeForName("WebServicePlugin"));
		
		ArrayList<WebService> services = new ArrayList<WebService>();
		
		for (ESPK child: children) {
			
			Entity childEntity = es.getEntity(child);
			ESPK wsESPK = childEntity.getReferenceValue("webService");
			Entity wsEntity = es.getEntity(wsESPK);
			
			WebService ws = new WebService(wsEntity, this.session.getWebServiceGroupManager());
			services.add(ws);
			
		}
		
		return services;
	}

		// TODO Auto-generated method stub
		
	
}
